package com.xcc.viewlibrary;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.OvershootInterpolator;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

/**
 * 用于TabBar背景动画
 */
public class TabBarAnimView extends View {
    public TabBarAnimView(Context context) {
        super(context);
        init(context, null);
    }

    public TabBarAnimView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public TabBarAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public TabBarAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    protected void init(Context context, AttributeSet attrs) {
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabBarAnimView);
            color = a.getColor(R.styleable.TabBarAnimView_tColor, 0xFF000000);
            tabNumb = a.getInt(R.styleable.TabBarAnimView_tNumb, 4);
            maxDia = a.getDimension(R.styleable.TabBarAnimView_tMaxDia, 4);
            minDia = a.getDimension(R.styleable.TabBarAnimView_tMinDia, 4);
            a.recycle();
        }
        addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
            public void onViewAttachedToWindow(View v) {
                isViewAttachedToWindow = true;
            }

            public void onViewDetachedFromWindow(View v) {
                isViewAttachedToWindow = false;
            }
        });
        currentIndex = -1;
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(color);
        if (BuildConfig.DEBUG) paint.setStrokeWidth(3);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!isViewAttachedToWindow) return;
        if (getWidth() == 0) return;
        if (type == 1) {
            onFirstDraw(canvas);
        } else if (type == 2) onMoveAnim(canvas);
    }

    private void onFirstDraw(Canvas canvas) {
        canvas.drawCircle(getCircleX(currentIndex), getCircleY(), cDia / 2, paint);
    }

    private void onMoveAnim(Canvas canvas) {
        final int i = stepTime / 3;
        float currentCircleX = getCircleX(currentIndex);//起始位置
        float selectCircleX = getCircleX(selectIndex);//目标位置
        boolean toRight = selectCircleX > currentCircleX;//向右 -->
        float circleY = getCircleY();
        int runTime = i << 1;
        if (currStepTime < runTime) {//阶段一
            float circleX = (selectCircleX - currentCircleX) * currStepTime / runTime + currentCircleX;
            canvas.drawCircle(circleX, circleY, maxDia / 2, paint);//绘制大圆

            Path path = new Path();
            path.moveTo(circleX, circleY - maxDia / 2);//大圆上部定点

            //计算小圆位置
            float cDist = currentCircleX - circleX;//圆心距离
            float abs = Math.abs(cDist);
            float minCX;//小圆x
            if (abs < maxDia) {//距离小于直径
                minCX = currentCircleX;
            } else minCX = circleX + (toRight ? -maxDia : maxDia);
            //canvas.drawCircle(minCX, circleY, minDia / 2, paint);//用于定位的小圆
            if (toRight) {
                minCX -= minDia;
            } else minCX += minDia;
            //二次贝塞尔曲线不好看
            /*path.quadTo(minCX, circleY, circleX, circleY + maxDia / 2);*/
            path.cubicTo(minCX, circleY - minDia / 2
                    , minCX, circleY + minDia / 2
                    , circleX, circleY + maxDia / 2);//三次
            path.close();
            canvas.drawPath(path, paint);
        } else {//阶段二
            canvas.drawCircle(selectCircleX, circleY, maxDia / 2, paint);//绘制大圆

            Path path = new Path();
            path.moveTo(selectCircleX, circleY - maxDia / 2);//大圆上部定点
            int overTime = stepTime - currStepTime;
            float v = maxDia * overTime / i;
            float minCX = selectCircleX + (toRight ? -v : v);//小圆x
            //canvas.drawCircle(minCX, circleY, minDia / 2, paint);
            if (toRight) {
                minCX -= minDia;
            } else minCX += minDia;
            /*path.quadTo(minCX, circleY, circleX, circleY + maxDia / 2);*/
            path.cubicTo(minCX, circleY - minDia / 2
                    , minCX, circleY + minDia / 2
                    , selectCircleX, circleY + maxDia / 2);//三次
            path.close();
            canvas.drawPath(path, paint);
        }
    }

    private boolean isViewAttachedToWindow;
    private int tabNumb;//tab数量
    private int color;
    private float minDia; //小圆直径
    private float maxDia;//大圆直径
    private int currentIndex;//当前选中 -1表示没有选中
    private int selectIndex;//选中 从0开始
    private int waitSelectIndex;//等待选中
    private Paint paint;
    private int type;//绘制模式 1开始位置的绘制
    private float cDia;
    private static final int stepTime = 480;//绘制步进时长 分三个阶段
    private int currStepTime;//当前步进时长
    private boolean runAnim;//执行动画中

    /**
     * @param index 选中哦index
     */
    private float getCircleX(int index) {
        float tabW = getWidth() * 1.0f / tabNumb;
        return tabW * (index + 0.5f);
    }

    //获取高度一半作为圆中心点
    private float getCircleY() {
        return getHeight() / 2.0f;
    }

    public void setSelectIndex(int selectIndex) {
        if (currentIndex == -1) {
            currentIndex = selectIndex;
            this.selectIndex = selectIndex;
            openFirstAnim();
        } else {
            this.waitSelectIndex = selectIndex;
            if (runAnim) return;
            if (currentIndex == selectIndex) {
                openFirstAnim();
                return;
            }
            runAnim = true;
            this.selectIndex = selectIndex;
            openMoveAnim();
        }
    }

    private void openFirstAnim() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(minDia, maxDia);
        valueAnimator.addUpdateListener(animation -> {
            type = 1;
            cDia = (Float) animation.getAnimatedValue();
            if (!isViewAttachedToWindow) return;
            invalidate();
        });
        valueAnimator.setInterpolator(new OvershootInterpolator());//回弹
        valueAnimator.setDuration(500);
        valueAnimator.start();
    }

    private void openMoveAnim() {
        //计算位置
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, stepTime);
        valueAnimator.addUpdateListener(animation -> {
            type = 2;
            currStepTime = (Integer) animation.getAnimatedValue();
            if (!isViewAttachedToWindow) return;
            invalidate();
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator animation) {
                currentIndex = selectIndex;
                runAnim = false;
                startWaitSelect();
            }
        });
        valueAnimator.setDuration(stepTime);
        valueAnimator.start();
    }

    private void startWaitSelect() {
        if (waitSelectIndex == currentIndex) return;
        setSelectIndex(waitSelectIndex);
    }
}
